﻿namespace ZGDisassembler.Core;

/// <summary>
/// 强制解析
/// </summary>
public class LineRecode
{
	/// <summary>
	/// 强制解析长度
	/// </summary>
	public byte Length { get; set; } = 1;
	/// <summary>
	/// 强制解析类型
	/// </summary>
	public DecodeType Type { get; set; } = DecodeType.Data;
}

/// <summary>
/// 编译器环境
/// </summary>
public class AppEnv
{

	#region 属性
	/// <summary>
	/// 编译器配置
	/// </summary>
	public Config AppConfig { get; set; } = new();
	/// <summary>
	/// 文件读取起始位置
	/// </summary>
	public uint BaseAddress { get; set; } = 0;
	/// <summary>
	/// 文件读取长度
	/// </summary>
	public uint FileReadLength { get; set; } = 0;
	/// <summary>
	/// 文件数据长度
	/// </summary>
	public uint FileDataLength => FileData == null ? 0 : (uint)FileData.Length;
	/// <summary>
	/// 所有结果行，key为Org地址
	/// </summary>
	public Dictionary<uint, ResultLine> AllResult { get; set; } = new();
	/// <summary>
	/// 重新解析的行
	/// </summary>
	public Dictionary<uint, LineRecode> AllRecodeLine { get; set; } = new();
	/// <summary>
	/// 结果行号与分解结果Org对应
	/// </summary>
	public Dictionary<uint, (uint OrgAddress, uint BaseAddress)> ResultLineNumberMap { get; set; } = new();
	/// <summary>
	/// 反编译起始地址
	/// </summary>
	internal uint OrgStart { get; set; } = 0;
	/// <summary>
	/// 反编译结束地址
	/// </summary>
	internal uint OrgEnd { get; set; } = 0;
	/// <summary>
	/// 所有标签
	/// </summary>
	internal Dictionary<uint, string> AllLabels { get; set; } = new();
	/// <summary>
	/// 所有原标签
	/// </summary>
	internal Dictionary<uint, string> OrgLabels { get; set; } = new();
	/// <summary>
	/// 文件数据
	/// </summary>
	private byte[] FileData { get; set; }
	#endregion 属性

	#region 设置文件数据
	public void SetData(byte[] data, uint fileStartPosition, uint? readLength = null)
	{
		FileData = data;
		BaseAddress = fileStartPosition;
		FileReadLength = readLength ?? FileDataLength;
	}
	#endregion 设置文件数据

	#region 获取文件数据
	internal Span<byte> GetData(uint index, byte length = 1)
	{
		var result = new List<byte>();
		for (var i = 0; i < length; ++i, ++index)
		{
			if (index >= FileData.Length)
				return null;

			result.Add(FileData[index]);
		}
		return result.ToArray();
	}
	#endregion 获取文件数据

	#region 读取替换的Label
	/// <summary>
	/// 读取替换的Label
	/// </summary>
	/// <param name="filePaths">读取的替换Label路径</param>
	/// <exception cref="ArgumentException"></exception>
	public void ReadReplaceLabel(params string[] filePaths)
	{
		OrgLabels.Clear();
		if (filePaths == null)
			return;

		for (var fileIndex = 0; fileIndex < filePaths.Length; fileIndex++)
		{
			var filePath = filePaths[fileIndex];
			if (!File.Exists(filePath))
				return;

			var lines = File.ReadAllLines(filePath, Encoding.UTF8);
			for (var i = 0; i < lines.Length; ++i)
			{
				var line = lines[i];
				line = Regex.Replace(line, ";.*", "");
				if (string.IsNullOrWhiteSpace(line))
					continue;

				var part = Regex.Split(lines[i], "\\s*=\\s*");
				if (part.Length != 2)
					throw new ArgumentException($"第 {i + 1} 行，标记格式错误");

				if (string.IsNullOrWhiteSpace(part[0]))
					throw new ArgumentException($"第 {i + 1} 行，标签错误，不能为空白");

				var address = Utils.CheckNumber(part[1]);
				if (address == null)
					throw new ArgumentException($"第 {i + 1} 行，解析值错误");

				if (OrgLabels.ContainsKey(address.Value))
					OrgLabels[address.Value] = part[0];
				else
					OrgLabels.Add(address.Value, part[0]);
			}
		}
	}
	#endregion 读取替换的Label

	#region 获取地址标签
	/// <summary>
	/// 获取地址标签
	/// </summary>
	/// <param name="address">地址</param>
	/// <returns></returns>
	internal string? GetLabel(uint address)
	{
		if (AppConfig.ReplaceLabel && OrgLabels.TryGetValue(address, out var label))
			return label;

		if (AppConfig.AbleLabel && AllLabels.TryGetValue(address, out label))
			return label;

		return null;
	}
	#endregion 获取地址标签

}
